package com.qiyi.player.core.video.provider.coreprovider
{
   import flash.events.EventDispatcher;
   import com.qiyi.player.core.video.file.corefile.ICoreFile;
   import com.qiyi.player.core.model.IMovie;
   import com.qiyi.player.core.video.decoder.IDecoder;
   import com.qiyi.player.core.player.coreplayer.ICorePlayer;
   import com.qiyi.player.core.video.provider.actors.providertile.HttpProvider;
   import com.qiyi.player.core.video.file.actors.datatile.IFlvBlock;
   import com.qiyi.player.core.model.impls.Segment;
   import com.qiyi.player.base.logging.ILogger;
   import com.qiyi.player.core.Config;
   import com.qiyi.player.core.video.file.actors.MediaUtils;
   import com.qiyi.player.core.model.impls.Keyframe;
   import com.qiyi.player.base.pub.EnumItem;
   import com.qiyi.player.core.video.events.ProviderEvent;
   import com.qiyi.player.core.video.provider.actors.providertile.InternetProvider;
   import com.qiyi.player.core.video.def.DataSourceTypeEnum;
   import com.qiyi.player.core.video.file.actors.datatile.FlvBlock;
   import com.qiyi.player.base.logging.Log;
   
   public class CoreProvider extends EventDispatcher implements ICoreProvider
   {
      
      public function CoreProvider(param1:ICoreFile, param2:IDecoder) {
         this._log = Log.getLogger("com.qiyi.player.core.video.provider.coreprovider.CoreProvider");
         super();
         this._file = param1;
         this._decoder = param2;
         this._holder = this._file.holder;
         this._movie = this._file.movie;
         this._log.debug("CoreProvider has been created!");
      }
      
      private var _file:ICoreFile;
      
      private var _movie:IMovie;
      
      private var _seeked:Boolean = false;
      
      private var _seekTime:int;
      
      private var _loadingFailed:Boolean = false;
      
      private var _decoder:IDecoder;
      
      private var _retryCount:int = 0;
      
      private var _holder:ICorePlayer;
      
      private var _saveTime:int = 0;
      
      private var _provider:HttpProvider;
      
      private var _loadingBlock:IFlvBlock;
      
      private var _segmentHack:Segment = null;
      
      private var _log:ILogger;
      
      public function get loadingFailed() : Boolean {
         return this._loadingFailed;
      }
      
      public function get loadingBlock() : IFlvBlock {
         return this._loadingBlock;
      }
      
      public function drive() : void {
         var _loc1_:* = 0;
         var _loc2_:* = 0;
         if((this._file.eof) || (this._loadingFailed) || !this._movie.ready)
         {
            return;
         }
         if(this.getLoadComplete())
         {
            return;
         }
         if(this._seeked)
         {
            this._segmentHack = null;
            this.loadNextBlock();
         }
         else
         {
            _loc1_ = this._file.bufferLength;
            if(this._provider)
            {
               if(_loc1_ - this._decoder.time < Config.PRELOAD_NEXT_SEGMENT && !(this._loadingBlock == this._file.findBlockAt(this._file.readingIndex)) && !MediaUtils.verifyFlvBlockContinuous(this._file.findBlockAt(this._file.readingIndex),this._loadingBlock))
               {
                  if(!this.verifyOrderContinuous(this._file.findBlockAt(this._file.readingIndex),this._loadingBlock))
                  {
                     if((this._provider.segment) && (this._segmentHack) && this._provider.segment == this._segmentHack)
                     {
                        this._loadingFailed = true;
                        this._segmentHack = null;
                        this._log.info("CoreProvider drive error by meta source!");
                        this.stopLoading();
                     }
                     else
                     {
                        this._segmentHack = this._provider.segment;
                        this.stopLoading();
                        this.loadNextBlock();
                     }
                  }
                  else
                  {
                     this._segmentHack = null;
                  }
               }
               else
               {
                  this._segmentHack = null;
               }
            }
            else
            {
               this._segmentHack = null;
               _loc2_ = this._holder.runtimeData.endTime;
               if(_loc2_ == 0 && (this._holder.runtimeData.skipTrailer))
               {
                  _loc2_ = this._file.movie.trailerTime;
               }
               if((_loc2_ == 0 || _loc1_ < _loc2_) && _loc1_ - this._decoder.time < Config.PRELOAD_NEXT_SEGMENT)
               {
                  this.loadNextBlock();
               }
            }
         }
      }
      
      public function set openSelectPlay(param1:Boolean) : void {
      }
      
      public function stopLoading() : void {
         this.destroyProvider();
         if(this._loadingBlock)
         {
            this._loadingBlock.loading = false;
         }
         this._loadingBlock = null;
      }
      
      public function clear() : void {
         this.destroyProvider();
         if(this._loadingBlock)
         {
            this._loadingBlock.loading = false;
         }
         this._loadingBlock = null;
         this._loadingFailed = false;
         this._retryCount = 0;
         this._seeked = false;
         this._seekTime = 0;
         this._segmentHack = null;
      }
      
      public function prepareSwitchMediaData() : void {
         this.destroyProvider();
         if(this._loadingBlock)
         {
            this._loadingBlock.loading = false;
         }
         this._loadingBlock = null;
         this._loadingFailed = false;
         this._retryCount = 0;
         this._seeked = false;
         this._seekTime = 0;
         this._segmentHack = null;
      }
      
      public function retry() : void {
         if(this._provider)
         {
            this._provider.stopAndReload();
         }
      }
      
      private function verifyOrderContinuous(param1:IFlvBlock, param2:IFlvBlock) : Boolean {
         var _loc3_:int = this._file.blockCount;
         var _loc4_:IFlvBlock = null;
         var _loc5_:IFlvBlock = null;
         var _loc6_:* = false;
         var _loc7_:* = 0;
         while(_loc7_ < _loc3_)
         {
            _loc4_ = this._file.findBlockAt(_loc7_);
            if(_loc4_ == param1)
            {
               _loc6_ = true;
            }
            if(_loc6_)
            {
               if(_loc7_ != _loc3_ - 1)
               {
                  _loc5_ = this._file.findBlockAt(_loc7_ + 1);
                  if(_loc5_ == param2)
                  {
                     return MediaUtils.verifyFlvBlockContinuous(_loc4_,_loc5_);
                  }
                  if(!MediaUtils.verifyFlvBlockContinuous(_loc4_,_loc5_))
                  {
                     return false;
                  }
               }
            }
            _loc7_++;
         }
         return false;
      }
      
      private function calcEndPosition(param1:int) : int {
         var _loc6_:IFlvBlock = null;
         var _loc7_:Segment = null;
         var _loc8_:Keyframe = null;
         var _loc9_:* = 0;
         var _loc2_:* = -1;
         var _loc3_:* = -1;
         var _loc4_:IFlvBlock = this._file.findBlockAt(param1);
         if(this._file.blockCount - 1 != param1)
         {
            _loc6_ = this._file.findBlockAt(param1 + 1);
            if(_loc6_.segment == _loc4_.segment)
            {
               _loc2_ = _loc6_.startTime;
               _loc3_ = _loc6_.startPosition;
            }
         }
         if(_loc2_ == -1)
         {
            _loc2_ = _loc4_.segment.endTime + 2;
         }
         var _loc5_:int = this._holder.runtimeData.endTime;
         if(_loc5_ == 0 && (this._holder.runtimeData.skipTrailer))
         {
            _loc5_ = this._movie.trailerTime;
         }
         this._saveTime = 0;
         if(_loc5_ > 0)
         {
            _loc7_ = this._movie.getSegmentByTime(_loc5_);
            if(_loc2_ >= _loc5_)
            {
               _loc2_ = _loc5_;
               this._saveTime = _loc7_.endTime - _loc5_;
               if(_loc5_ == this._movie.trailerTime && !(_loc7_.index == this._movie.curDefinition.segmentCount - 1))
               {
                  this._saveTime = this._saveTime + this._movie.curDefinition.findSegmentAt(_loc7_.index + 1).totalTime;
               }
            }
            if(_loc7_ == _loc4_.segment)
            {
               _loc8_ = _loc7_.getKeyframeByTime(_loc5_);
               if(_loc8_)
               {
                  _loc9_ = _loc8_.position + _loc8_.lenPos;
                  if(_loc3_ == -1 || _loc3_ >= _loc9_)
                  {
                     _loc3_ = _loc9_;
                  }
               }
            }
         }
         return _loc3_;
      }
      
      public function seek(param1:int) : void {
         this._log.info("CoreProvider seeking: " + param1);
         this._seeked = true;
         this._seekTime = param1;
         this._retryCount = 0;
         this._segmentHack = null;
      }
      
      private function reloadBlock(param1:IFlvBlock, param2:EnumItem, param3:int) : void {
         dispatchEvent(new ProviderEvent(ProviderEvent.Evt_WillLoad));
         this._loadingBlock = param1;
         this._loadingBlock.expectEndPosition = param3;
         this._loadingBlock.loading = true;
         this._loadingBlock.endAppend();
         this.createProvider(param2);
         var _loc4_:* = 0;
         if(param1.size > 0)
         {
            _loc4_ = this._loadingBlock.endPosition;
         }
         else if((param1.startKeyframe) && !(param1.startKeyframe.index == 0))
         {
            _loc4_ = param1.startKeyframe.position;
         }
         
         if(!this._provider.load(_loc4_))
         {
            this.onProviderFailed(null);
         }
      }
      
      private function startLoadBlock(param1:IFlvBlock, param2:EnumItem, param3:int) : void {
         dispatchEvent(new ProviderEvent(ProviderEvent.Evt_WillLoad));
         this._loadingBlock = param1;
         this._loadingBlock.expectEndPosition = param3;
         this._loadingBlock.loading = true;
         this.createProvider(param2);
         var _loc4_:* = 0;
         if((param1.startKeyframe) && !(param1.startKeyframe.index == 0))
         {
            _loc4_ = param1.startKeyframe.position;
         }
         if(!this._provider.load(_loc4_))
         {
            this.onProviderFailed(null);
         }
      }
      
      private function createProvider(param1:EnumItem) : void {
         this._loadingBlock.dataSourceType = param1;
         switch(param1)
         {
            case DataSourceTypeEnum.CDN:
               this._provider = new InternetProvider(this._loadingBlock,this._holder);
               break;
         }
         this._provider.addEventListener(ProviderEvent.Evt_Connected,this.onProviderConnected);
         this._provider.addEventListener(ProviderEvent.Evt_LoadComplete,this.onProviderComplete);
         this._provider.addEventListener(ProviderEvent.Evt_Failed,this.onProviderFailed);
      }
      
      private function destroyProvider() : void {
         if(this._provider == null)
         {
            return;
         }
         this._provider.removeEventListener(ProviderEvent.Evt_Connected,this.onProviderConnected);
         this._provider.removeEventListener(ProviderEvent.Evt_LoadComplete,this.onProviderComplete);
         this._provider.removeEventListener(ProviderEvent.Evt_Failed,this.onProviderFailed);
         this._provider.destroy();
         this._provider = null;
      }
      
      private function onProviderConnected(param1:ProviderEvent) : void {
         dispatchEvent(new ProviderEvent(ProviderEvent.Evt_StartLoad));
      }
      
      private function onProviderComplete(param1:ProviderEvent) : void {
         this.destroyProvider();
         this._loadingBlock.endOfFile = Boolean(param1.data);
         if(!this._loadingBlock.discard && this._saveTime > 0)
         {
            this._holder.pingBack.sendSaveBandWidth(this._saveTime,2);
         }
         this.onBlockComplete();
      }
      
      private function onProviderFailed(param1:ProviderEvent) : void {
         if(!this._loadingBlock.limitUniqueSource)
         {
            switch(this._loadingBlock.dataSourceType)
            {
               case DataSourceTypeEnum.CDN:
                  this.destroyProvider();
                  this.onBlockFailed();
                  break;
            }
         }
         else
         {
            this.destroyProvider();
            this.onBlockFailed();
         }
      }
      
      private function onBlockFailed() : void {
         this._loadingBlock.loading = false;
         this._saveTime = 0;
         this._loadingFailed = true;
         if(this._loadingBlock == this._file.findBlockAt(this._file.readingIndex) && this._loadingBlock.dataSourceType == DataSourceTypeEnum.CDN)
         {
            if(this._loadingBlock.discard)
            {
               this._file.removeBlock(this._loadingBlock);
            }
            dispatchEvent(new ProviderEvent(ProviderEvent.Evt_Failed));
         }
         else if(this._loadingBlock.discard)
         {
            this._file.removeBlock(this._loadingBlock);
         }
         
         this._loadingBlock = null;
      }
      
      private function onBlockComplete() : void {
         var _loc1_:IFlvBlock = null;
         var _loc2_:* = 0;
         var _loc3_:* = 0;
         this._loadingBlock.loading = false;
         this._saveTime = 0;
         if(this._loadingBlock.discard)
         {
            this._file.removeBlock(this._loadingBlock);
            this._retryCount++;
            if(this._retryCount > 3)
            {
               this._loadingFailed = true;
               if(this._seeked)
               {
                  dispatchEvent(new ProviderEvent(ProviderEvent.Evt_Failed));
               }
            }
         }
         else
         {
            this._retryCount = 0;
            _loc1_ = null;
            _loc2_ = this._file.findBlockIndex(this._loadingBlock);
            if(_loc2_ < this._file.blockCount - 1)
            {
               _loc1_ = this._file.findBlockAt(_loc2_ + 1);
            }
            if((_loc1_) && _loc1_.segment == this._loadingBlock.segment)
            {
               _loc3_ = this._file.bufferLength;
               if(_loc3_ >= this._loadingBlock.segment.endTime)
               {
                  _loc3_ = this._loadingBlock.segment.endTime;
               }
               this._holder.pingBack.sendSaveBandWidth(_loc3_ - this._loadingBlock.endTime,3);
            }
         }
         this._loadingBlock = null;
      }
      
      private function loadNextBlock() : void {
         if(this._seeked)
         {
            this.executeSeek();
         }
         else if(this._provider == null)
         {
            if(this._file.readingIndex == -1)
            {
               this.executeSeekReading();
            }
            else
            {
               this.executeNextLoad();
            }
         }
         
      }
      
      private function executeSeek() : void {
         var _loc5_:IFlvBlock = null;
         var _loc6_:* = 0;
         var _loc1_:Segment = this._movie.getSegmentByTime(this._seekTime);
         var _loc2_:Keyframe = _loc1_.getKeyframeByTime(this._seekTime);
         var _loc3_:* = 0;
         if(_loc2_)
         {
            _loc3_ = _loc2_.position;
         }
         var _loc4_:int = this._file.findBlockIndexFrom(_loc1_,_loc3_);
         if(_loc4_ == -1)
         {
            this._loadingFailed = false;
            this._file.readingIndex = this.createBlock(_loc1_,_loc3_);
         }
         else if(this._file.readingIndex != -1)
         {
            _loc5_ = this._file.findBlockAt(_loc4_);
            if(!_loc5_.complete && !_loc5_.loading && (_loc4_ == this._file.blockCount - 1 || _loc4_ < this._file.blockCount - 1 && !MediaUtils.verifyFlvBlockContinuous(_loc5_,this._file.findBlockAt(_loc4_ + 1))))
            {
               this.stopLoading();
               this._holder.pingBack.sendSaveBandWidth(_loc5_.endTime - this._seekTime,3);
               _loc6_ = this.calcEndPosition(_loc4_);
               this._loadingFailed = false;
               this.reloadBlock(_loc5_,DataSourceTypeEnum.CDN,_loc6_);
            }
         }
         else
         {
            this._file.seek(this._seekTime);
         }
         
         this._seeked = false;
      }
      
      private function executeSeekReading() : void {
         this._log.debug("executeSeekReading:seeked=false,loading=false,readingIndex=-1");
         var _loc1_:Number = this._decoder.time + this._decoder.bufferLength * 1000;
         this._movie.seek(_loc1_);
         if(this._movie.curSegment.currentKeyframe == null)
         {
            _loc1_ = this._movie.curSegment.startTime;
            this._file.seek(_loc1_);
            this._seeked = true;
            this._seekTime = _loc1_;
            this._decoder.seek(_loc1_ == 0?100:_loc1_);
         }
         else
         {
            _loc1_ = this._movie.getSeekTime();
            this._file.seek(_loc1_);
            this._seeked = true;
            this._seekTime = _loc1_;
         }
      }
      
      private function executeNextLoad() : void {
         var _loc1_:* = 0;
         var _loc2_:* = 0;
         var _loc4_:* = 0;
         var _loc5_:Segment = null;
         this._log.debug("executeNextLoad");
         _loc1_ = this._file.readingIndex;
         _loc2_ = this._file.blockCount;
         while(_loc1_ < _loc2_ - 1)
         {
            if(!MediaUtils.verifyFlvBlockContinuous(this._file.findBlockAt(_loc1_),this._file.findBlockAt(_loc1_ + 1)))
            {
               break;
            }
            _loc1_++;
         }
         var _loc3_:IFlvBlock = this._file.findBlockAt(_loc1_);
         if(_loc3_.endPosition < _loc3_.segment.totalBytes && !_loc3_.endOfFile)
         {
            this._holder.pingBack.sendSaveBandWidth(_loc3_.duration,3);
            if(_loc3_.complete)
            {
               this.createBlock(_loc3_.segment,_loc3_.endPosition);
            }
            else
            {
               _loc4_ = this.calcEndPosition(_loc1_);
               this.reloadBlock(_loc3_,DataSourceTypeEnum.CDN,_loc4_);
            }
         }
         else if(_loc3_.segment.index < this._movie.curDefinition.segmentCount - 1)
         {
            _loc5_ = this._movie.curDefinition.findSegmentAt(_loc3_.segment.index + 1);
            this.createBlock(_loc5_,0);
         }
         
      }
      
      private function createBlock(param1:Segment, param2:int) : int {
         var _loc3_:IFlvBlock = new FlvBlock(param1,param1.getKeyframeByPosition(param2),this._holder,false);
         this.stopLoading();
         var _loc4_:int = this._file.addBlock(_loc3_);
         var _loc5_:int = this.calcEndPosition(_loc4_);
         this._loadingFailed = false;
         this.startLoadBlock(_loc3_,DataSourceTypeEnum.CDN,_loc5_);
         return _loc4_;
      }
      
      private function getLoadComplete() : Boolean {
         var _loc1_:int = this._file.bufferLength;
         var _loc2_:int = this._holder.runtimeData.endTime;
         if(_loc2_ == 0 && (this._holder.runtimeData.skipTrailer))
         {
            _loc2_ = this._movie.trailerTime;
         }
         var _loc3_:int = _loc2_ > 0?_loc2_:this._movie.duration;
         if(_loc1_ >= _loc3_ || _loc3_ - _loc1_ < 2000)
         {
            return true;
         }
         return false;
      }
      
      public function destroy() : void {
         this.destroyProvider();
         this._file = null;
         this._movie = null;
         this._decoder = null;
         this._holder = null;
         if(this._loadingBlock)
         {
            this._loadingBlock.loading = false;
         }
         this._loadingBlock = null;
      }
   }
}
